package me.spring.cloud.common.components.ips.convert;


import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

public class NewQQwry2List {

  private File qqwryFile;
  private static ReentrantLock lock = new ReentrantLock();
  private byte[] data;
  private long firstIndexOffset;
  private long lastIndexOffset;
  private long totalIndexCount;
  private static final long IP_RECORD_LENGTH = 10;

  public NewQQwry2List(String filePath) throws Exception {
    this.qqwryFile = new File(filePath);
    load();
  }

  private void load() throws Exception {
    ByteArrayOutputStream out = null;
    FileInputStream in = null;
    lock.lock();
    try {
      out = new ByteArrayOutputStream();
      byte[] b = new byte[1024];
      in = new FileInputStream(qqwryFile);
      while (in.read(b) != -1) {
        out.write(b);
      }
      data = out.toByteArray();
      firstIndexOffset = read4ByteAsLong(0);
      lastIndexOffset = read4ByteAsLong(4);
      totalIndexCount = (lastIndexOffset - firstIndexOffset) / IP_RECORD_LENGTH + 1;
      in.close();
      out.close();
    } finally {
      try {
        if (out != null) {
          out.close();
        }
        if (in != null) {
          in.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
      lock.unlock();
    }
  }

  private long read4ByteAsLong(final int offset) {
    long val = data[offset] & 0xFF;
    val |= (data[offset + 1] << 8L) & 0xFF00L;
    val |= (data[offset + 2] << 16L) & 0xFF0000L;
    val |= (data[offset + 3] << 24L) & 0xFF000000L;
    return val;
  }

  public List<String[]> trans2List() {
    lock.lock();
    try {
      return execute();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
    return null;
  }

  private List<String[]> execute() {
    long low = 0;
    long high = totalIndexCount;
    long mid = 0;
    List<String[]> list = new ArrayList<>();
    while (low <= high) {
      mid = low;
      long indexIP = read4ByteAsLong((int) (firstIndexOffset + (mid - 1) * IP_RECORD_LENGTH));
      long indexIPNext = read4ByteAsLong((int) (firstIndexOffset + mid * IP_RECORD_LENGTH));
      list.add(new String[]{
          String.valueOf(indexIP),
          String.valueOf(indexIPNext),
          readString(
              (int) read3ByteAsLong((int) (firstIndexOffset + (mid - 1) * IP_RECORD_LENGTH + 4))),
          readString(
              (int) read3ByteAsLong((int) (firstIndexOffset + (mid - 1) * IP_RECORD_LENGTH + 7)))
      });
      low++;
    }
    return list;
  }

  private long read3ByteAsLong(final int offset) {
    long val = data[offset] & 0xFF;
    val |= (data[offset + 1] << 8) & 0xFF00;
    val |= (data[offset + 2] << 16) & 0xFF0000;
    return val;
  }

  private String readString(int offset) {
    final byte[] b = new byte[128];
    int i;
    try {
      for (i = 0, b[i] = data[offset++]; b[i] != 0; b[++i] = data[offset++]) {
      }
      return new String(b, 0, i, "GBk");
    } catch (Exception e) {
      return new String("");
    }
  }
}
